我們在使用Config的時候,常見會有幾種方式
IConfiguration
的物件,並且用Key取得其值。{
"line": {
"channelId": "line_channel_id",
"channelSecret": "line_channel_secret",
"info": {
"name": "line_bot_name",
"pictureUrl": "line_bot_picture_url"
}
},
"facebook": {
"pageId": "facebook_page_id",
"accessToken": "facebook_page_access_token",
"appSecret": "facebook_app_secret"
},
"telegram": {
"botToken": "telegram_bot_token"
}
}
直接注入IConfiguration
的方式Program.cs
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var serviceProvider = new ServiceCollection()
.AddSingleton<IConfiguration>(configuration)
.AddTransient<LineService>()
.BuildServiceProvider();
var lineService = serviceProvider.GetService<LineService>();
lineService!.PrintLineAppName();
LineService.cs
public class LineService
{
private readonly IConfiguration _configuration;
public LineService(IConfiguration configuration)
{
_configuration = configuration;
}
public void PrintLineAppName()
{
Console.WriteLine(_configuration["line:info:name"]);
}
}
我們透過_configuration["line:info:name"]
取得了line_bot_name
但是說真的這方式並不這麼推薦使用,原因大概如下
我會用這種方式通常有兩種原因
較常見的是綁定到物件
先添加我們要綁定的物件LineSetting.cs
public class LineSetting
{
public string ChannelId { get; set; }
public string ChannelSecret { get; set; }
public LineSetting.LineInfo Info { get; set; }
public class LineInfo
{
public string Name { get; set; }
public string PictureUrl { get; set; }
}
}
並且調整LineService.cs
為注入LineSetting.cs
的板本
public class LineService
{
private readonly LineSetting _lineSetting;
public LineService(LineSetting lineSetting)
{
_lineSetting = lineSetting;
}
public void PrintLineAppName()
{
Console.WriteLine(_lineSetting.Info.Name);
}
}
主要有兩種方式進行綁定
Program.cs
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var lineSetting = configuration
.GetSection("line")
.Get<LineSetting>();
var serviceProvider = new ServiceCollection()
.AddSingleton(lineSetting)
.AddTransient<LineService>()
.BuildServiceProvider();
var lineService = serviceProvider.GetService<LineService>();
lineService!.PrintLineAppName();
我們使用了 IConfiguration.GetSection("line")
來取得line
這個結點的IConfigurationGetSection
然後透過了IConfiguration.Get<LineSetting>()
方法取得了LineSetting
的物件,Get方法會直接幫你Return一個底下物件綁定好的物件
我們調整Program.cs
改使用Bind的方式來取得設定
// ... ConfigBuilder
var lineSetting = new LineSetting();
configuration
.GetSection("line")
.Bind(lineSetting);
// ... DI Setting
可以看見Bind跟Get其實相差不遠
只是Bind
是針對既有的執行個體做綁定Get
則是會回傳一個新的執行個體
這邊的環境變數指的不完全是程式的環境變數
包括系統的環境變數也被包含在其中
具體來說我不常用到他
顧名思義,可以讀取Cli 的值作為其Config來源
program.cs
var mapping = new Dictionary<string,string>()
{
["--line"] = "line",
["-f"] = "fb"
};
var configuration = new ConfigurationBuilder()
.AddCommandLine(args, mapping)
.AddCommandLine(args)
.Build();
Console.WriteLine(configuration["line:info:name"]);
Console.WriteLine(configuration["line"]);
Console.WriteLine(configuration["fb"]);
dotnet run line:info:name=linebot --line=lineChannelId -x FB_Page
Id
可以看見我們透過自訂mapping的方式將commandLine參數與對應的setting mapping在一起,也可以透過path的方式指定節點的值。
簡單方便粗暴
主要透過一個IEnumerable<KeyValuePair<stirng,string>>
作為資料來源
using Microsoft.Extensions.Configuration;
var memoryData = new Dictionary<string,string>()
{
["line:channelId"] = "ChannelId",
["line:channelSecret"] = "ChannelSecret",
["line:info:name"] = "Name",
["line:info:iconUrl"] = "IconUrl",
};
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(memoryData)
.Build();
Console.WriteLine(configuration["line:channelId"]);
Console.WriteLine(configuration["line:channelSecret"]);
Console.WriteLine(configuration["line:info:name"]);
Console.WriteLine(configuration["line:info:iconUrl"]);
使用上基本上通常就是建個Dictionary丟進去就對了
設定來源是檔案類型的FileConfiguarionSource.cs
public abstract class FileConfigurationSource : IConfigurationSource
{
public IFileProvider FileProvider { get; set; }
public string Path { get; set; }
public bool Optional { get; set; }
public bool ReloadOnChange { get; set; }
public int ReloadDelay { get; set; } = 250;
// others...
}
可以看見有IFileProvider
,可以決定要提供的檔案的實際提供者ConfigurationBuilder
會優先取設定的IFileProvider
,若無則建立一個PhysicalFileProvider
作為FileProvider
比較有趣的是Optional
,ReloadOnChange
,ReloadDelay
跟OnLoadException
這4個屬性
Optional
所代表的是這個設定來源是不是可選的,設為true
時代表即便沒有這個設定檔也沒關係appSettings.json
看見其作用。假設當前環境是 Stage,即便你忘了放appsettings.developer.json
也不會報錯,因為他的Optional是設為true的ReloadOnChange
,ReloadDelay
: 顧名思義,就是當檔案更新時要不要重讀設定檔,以及要延遲多久重新載入IFileProvider.Watch
來達到常見有好幾種,都是繼承自FileConfiguarionSource
主要介紹一下在dotnet 6 Host中設定json的方式
builder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
對比dotnet core 5以下的設定方式
builder.ConfigureAppConfiguration(builder=>builder.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true))
語意上清楚了多